package top.yehot.kettle.boot.service.impl;

import java.io.File;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.pentaho.di.repository.AbstractRepository;
import org.pentaho.di.repository.LongObjectId;
import org.pentaho.di.repository.ObjectId;
import org.pentaho.di.repository.RepositoryDirectoryInterface;
import org.pentaho.di.repository.RepositoryElementMetaInterface;
import org.pentaho.di.repository.RepositoryObjectType;
import org.pentaho.di.repository.StringObjectId;
import org.pentaho.di.repository.filerep.KettleFileRepository;
import org.pentaho.di.repository.kdr.KettleDatabaseRepository;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import lombok.AllArgsConstructor;
import top.yehot.cmm.util.core.base.BaseException;
import top.yehot.kettle.boot.core.SysConst;
import top.yehot.kettle.boot.core.utils.FileUtil;
import top.yehot.kettle.boot.core.utils.RepositoryUtil;
import top.yehot.kettle.boot.enums.KettleResEnum;
import top.yehot.kettle.boot.mapper.ScriptDelMapper;
import top.yehot.kettle.boot.mapper.ScriptMapper;
import top.yehot.kettle.boot.models.entity.Script;
import top.yehot.kettle.boot.models.entity.ScriptDel;
import top.yehot.kettle.boot.models.vo.script.ScriptRenameVO;
import top.yehot.kettle.boot.models.vo.script.ScriptUploadVO;
import top.yehot.kettle.boot.models.vo.script.ScriptVO;
import top.yehot.kettle.boot.service.ScriptService;

/**
 * 文件 服务实现类
 * 
 * @author lquan
 * @date 2022年6月1日 下午10:24:13
 */
@Service
@AllArgsConstructor
public class ScriptServiceImpl extends ServiceImpl<ScriptMapper, Script> implements ScriptService {

	private final ScriptDelMapper scriptDelMapper;
	
	@Override
	public List<ScriptVO> findScriptById(String repId, String dirId) {
		// 获取资源库
		AbstractRepository abstractRepository = RepositoryUtil.getRepository(repId);
		// 判断是文件或数据库资源库
		boolean isDbFile = false;
		
		RepositoryDirectoryInterface rdi = null;
		List<RepositoryElementMetaInterface> tmpScriptList = null;
		try {
			// 获取资源库目录树
			if (abstractRepository instanceof KettleDatabaseRepository) {
				isDbFile = true;
				rdi = abstractRepository.loadRepositoryDirectoryTree().findDirectory(new LongObjectId(Long.valueOf(dirId)));
			} else {
				rdi = abstractRepository.loadRepositoryDirectoryTree().findDirectory(dirId);
			}
			
			// 获取当前节点下[转化，作业]脚本
			tmpScriptList = abstractRepository.getJobAndTransformationObjects(rdi.getObjectId(), false);
		} catch (Exception e) {
			throw new BaseException(KettleResEnum.GET_SCRIPT_INFO_ERR);
		}
		// 获取当前节点下路径
		String rdiPath = FileUtil.removeEndSlash(rdi.getPath()).concat(FileUtil.separator);
		
		// 封装脚本信息
		List<ScriptVO> scriptList = tmpScriptList.stream().map(element -> {
			String fileType = element.getObjectType().getTypeDescription();
			String fullPath = rdiPath.concat(element.getName()).concat(SysConst.scriptTypeMap.get(fileType));
			return new ScriptVO()
					.setId(fileType + "@" + dirId + "@" + element.getObjectId().getId())
					.setName(element.getName())
					.setPath(fullPath)
					.setType(fileType);
		}).collect(Collectors.toList());
		
		// 数据库资源库补不全
		if (isDbFile) return scriptList;
		
		/* 文件资源库需要补全文件信息 */
		// 获取根路径
		String basePath = FileUtil.removeEndSlash(((KettleFileRepository) abstractRepository).getRepositoryMeta().getBaseDirectory());
		// 获取文件夹下所有文件信息
		File[] childrenFiles = new File(basePath + rdiPath).listFiles();
		Arrays.asList(childrenFiles).stream().forEach(fi -> {
			if (fi.isDirectory()) return;
			
			// 获取文件名称
			String fileName = fi.getName(); 
			// 获取文件后缀
			int lastPoint = fileName.lastIndexOf("."); 
			String typeFile = (lastPoint == -1 ? "" : fileName.substring(lastPoint + 1).toLowerCase());
			// 未统计到就重新统计
			if (!scriptList.stream().anyMatch(sc -> fileName.equals(sc.getName() + SysConst.scriptTypeMap.get(sc.getType())))) {
				scriptList.add(
					new ScriptVO()
						.setId(typeFile + "@" + dirId + "@" + dirId + fileName)
						.setName(fileName)
						.setPath(rdiPath.concat(fileName))
						.setType(typeFile)
				);
			}
		});
		return scriptList;
	}

	@Transactional
	@Override
	public void delete(String repId, String fileId) {
		AbstractRepository abstractRepository = RepositoryUtil.getRepository(repId);
		// 解析ID[类型，父路径，脚本ID]
		String[] idParser = fileId.split("@");
		// 根路径
		String basePath = null;
		
		ObjectId objId = null;
		if (abstractRepository instanceof KettleDatabaseRepository) {
			objId = new LongObjectId(Long.valueOf(idParser[2]));
		} else {
			objId = new StringObjectId(idParser[2]);
			basePath = FileUtil.removeEndSlash(((KettleFileRepository) abstractRepository).getRepositoryMeta().getBaseDirectory());
		}
		
		if (null != basePath) {
			Script script = baseMapper.selectOne(Wrappers.lambdaQuery(Script.class).eq(Script::getRepId, repId)
					.eq(Script::getName, idParser[2].replace(idParser[1], ""))
					.eq(Script::getFolderPath, idParser[1])
				);
			Optional.ofNullable(script).ifPresent(scri -> {
				baseMapper.deleteById(script.getId());
				
				ScriptDel scDel = new ScriptDel();
				BeanUtils.copyProperties(script, scDel);
				scDel.setDeleteTime(LocalDateTime.now());
				scriptDelMapper.insert(scDel);
			});
		}
		
		try {
			if (RepositoryObjectType.TRANSFORMATION.getTypeDescription().equals(idParser[0])) {
				// 删除转换
				abstractRepository.deleteTransformation(objId);
			} else if (RepositoryObjectType.JOB.getTypeDescription().equals(idParser[0])) {
				// 删除作业
				abstractRepository.deleteJob(objId);
			} else if (null != basePath) {
				// 删除文件
				new File(basePath + idParser[2]).delete();
			}
		} catch (Exception e) {
			log.error(KettleResEnum.DELETE_SCRITP_ERR.getMsg(), e);
			throw new BaseException(KettleResEnum.DELETE_SCRITP_ERR);
		}
		
	}

	@Transactional
	@Override
	public void upload(ScriptUploadVO param) {
		MultipartFile file = param.getFile();
		if (file.isEmpty()) return;
		
		AbstractRepository abstractRepository = RepositoryUtil.getRepository(param.getRepId());
		if (abstractRepository instanceof KettleFileRepository) {
			KettleFileRepository fileRepo = (KettleFileRepository) abstractRepository;
			// 获取根路径
			String basePath = FileUtil.removeEndSlash(fileRepo.getRepositoryMeta().getBaseDirectory());
			
			// 封装对象
			Script script = new Script();
			script.setRepId(param.getRepId());
			script.setName(file.getOriginalFilename());
			script.setFolderPath(param.getDirId());
			try {
				// 保存
				baseMapper.insert(script);
				// 上传文件
				FileUtils.copyInputStreamToFile(file.getInputStream(), new File(basePath + param.getDirId() + file.getOriginalFilename()));
			} catch (Exception e) {
				log.error(KettleResEnum.UPLOAD_SCRIPT_ERR.getMsg(), e);
				throw new BaseException(KettleResEnum.UPLOAD_SCRIPT_ERR);
			}
		}
	}

	@Override
	public void rename(ScriptRenameVO param) {
		AbstractRepository abstractRepository = RepositoryUtil.getRepository(param.getRepId());
		// 新文件名册
		String newName = param.getName();
		// 解析ID[类型，父路径，脚本ID]
		String[] idParser = param.getId().split("@");
		// 文件类型
		String fileType = idParser[0];
		
		ObjectId objId = null;
		ObjectId objPId = null; // 
		String basePath = null; // 根路径
		RepositoryDirectoryInterface rdi = null; // 获取资源库目录树
		try {
			if (abstractRepository instanceof KettleDatabaseRepository) {
				objId = new LongObjectId(Long.valueOf(idParser[2]));
				objPId = new LongObjectId(Long.valueOf(idParser[1]));
				rdi = abstractRepository.loadRepositoryDirectoryTree().findDirectory(objPId);
			} else {
				objId = new StringObjectId(idParser[2]);
				objPId = new StringObjectId(idParser[1]);
				rdi = abstractRepository.loadRepositoryDirectoryTree().findDirectory(objPId);
				basePath = FileUtil.removeEndSlash(((KettleFileRepository) abstractRepository).getRepositoryMeta().getBaseDirectory());
			}
		} catch (Exception e) {
			throw new BaseException(KettleResEnum.GET_REPO_ERR);
		}
		
		try {
			if (RepositoryObjectType.TRANSFORMATION.getTypeDescription().equals(fileType)) {
				List<RepositoryElementMetaInterface> list = abstractRepository.getTransformationObjects(objPId, false);
				if (list.stream().anyMatch(f -> f.getName().equals(newName))) {
					throw new BaseException(KettleResEnum.FILE_NAME_EXIST);
				}
				abstractRepository.renameTransformation(objId, rdi, newName);
			} else if (RepositoryObjectType.JOB.getTypeDescription().equals(fileType)) {
				List<RepositoryElementMetaInterface> list = abstractRepository.getTransformationObjects(objPId, false);
				if (list.stream().anyMatch(f -> f.getName().equals(newName))) {
					throw new BaseException(KettleResEnum.FILE_NAME_EXIST);
				}
				abstractRepository.renameJob(objId, rdi, newName);
			} else if (null != basePath) {
				// 文件全称
				String tmpNewName = newName + (StringUtils.hasText(idParser[0]) ? "." + idParser[0] : "");
				// 获取当前文件夹下所有文件，判断是否有名称相同文件
				File[] files = new File(basePath + idParser[1]).listFiles();
				for (File file : files) {
					if (file.getName().equals(tmpNewName)) {
						throw new BaseException(KettleResEnum.FILE_NAME_EXIST);
					}
				}
				
				File oldf = new File(basePath + idParser[2]);
				File newf = new File(basePath + idParser[1] + tmpNewName);
				oldf.renameTo(newf);
			}
		} catch (Exception e) {
			if (e instanceof BaseException) {
				throw (BaseException) e;
			} else {
				log.error(KettleResEnum.RENAME_SCRIPT_ERR.getMsg(), e);
				throw new BaseException(KettleResEnum.RENAME_SCRIPT_ERR);
			}
		}
	}

}
